#!/usr/bin/env python3
import argparse
import json
import os
import sys 
from shutil import move
from copy import deepcopy
from urllib.parse import urlparse
from typing import Dict
from typing import Tuple
from tempfile import mkstemp
from updwscfg import IsSudoAvailable, rpcf_system
import errno
import socket

g_passDlg = None
def GetTestPaths( path : str= None ) :
    dir_path = os.path.dirname(os.path.realpath(__file__))
    paths = []
    if path is None:
        curDir = dir_path
        paths.append( curDir + "/../../etc/rpcf" )
        paths.append( "/etc/rpcf")

        curDir += "/../test/"
        paths.append( curDir + "iftest" )
        paths.append( curDir + "btinrt" )
        paths.append( '../monitor/appmon' )
        if IsFeatureEnabled( 'testcases' ):
            paths.append( curDir + "actcancel" )
            paths.append( curDir + "asynctst" )
            paths.append( curDir + "evtest" )
            paths.append( curDir + "helloworld" )
            paths.append( curDir + "inproc" )
            paths.append( curDir + "katest" )
            paths.append( curDir + "prtest" )
            paths.append( curDir + "sftest" )
            paths.append( curDir + "stmtest" )
    else:
        paths.append( path )

    return paths

def IsFeatureEnabled( feature : str ) -> bool :
    features='@FEATURES@'
    feature = "+" + feature
    ret = features.find( feature )
    if ret == -1:
        return False
    return True

def ReadTestCfg( paths:list, name:str) :
    jsonVal = None
    for path in paths:
        try:
            cfgFile = path + "/" + name
            fp = open( cfgFile, "r" )
            jsonVal = [cfgFile, json.load(fp) ]
            fp.close()
        except Exception as err:
            continue

        return jsonVal
    return None

def GetPyTestPaths() :
    dir_path = os.path.dirname(os.path.realpath(__file__))
    paths = []
    paths.append( dir_path +
        "/../python/tests/sftest" )
    return paths

def UpdateTestCfg( pathVal, cfgList:list ):
    try:
        ifCfg = cfgList[ 0 ]
        authInfo = cfgList[ 1 ]
        jsonVal = pathVal[1]
        if not 'Objects' in jsonVal :
            return

        fileName = os.path.basename( pathVal[ 0 ] )
        oConns = cfgList[ 3 ]
        objs = jsonVal[ 'Objects' ]
        for elem in objs :
            if fileName == 'hwdesc.json' and len( oConns ) >= 2:
                ifCfg = oConns[ 1 ]
            elif fileName == 'btinrt.json' and len( oConns ) >= 3:
                ifCfg = oConns[ 2 ]
            elem[ 'IpAddress' ] = ifCfg[ 'IpAddress' ]
            elem[ 'PortNumber' ] = ifCfg[ 'PortNumber' ]
            elem[ 'Compression' ] = ifCfg[ 'Compression' ]
            elem[ 'EnableSSL' ] = ifCfg[ 'EnableSSL' ]
            elem[ 'EnableWS' ] = ifCfg[ 'EnableWS' ]
            if 'RouterPath' in ifCfg:
                elem[ 'RouterPath' ] = ifCfg[ 'RouterPath' ]
            else:
                elem[ 'RouterPath' ] = "/"
            if 'HasAuth' in ifCfg and ifCfg[ 'HasAuth' ] == 'true' :
                elem[ 'AuthInfo' ] = deepcopy( authInfo )
                if authInfo[ 'AuthMech'] == 'OAuth2':
                    if 'OA2ChkIp' in elem['AuthInfo']:
                        elem['AuthInfo'].pop( "OA2ChkIp")
                    if 'OA2ChkPort' in elem['AuthInfo']:
                        elem['AuthInfo'].pop( "OA2ChkPort")
                    if 'OA2SSL' in elem['AuthInfo']:
                        elem['AuthInfo'].pop( "OA2SSL")
            else :
                elem.pop( 'AuthInfo', None )
            bSSL = False
            if elem[ 'EnableSSL' ] == 'true' :
                bSSL = True
            if elem[ 'EnableWS' ] == 'true' :
                elem[ 'DestURL' ] = ifCfg[ 'DestURL' ]
                urlComp = urlparse( elem[ 'DestURL' ], scheme='https' )
                if urlComp.port is None :
                    if urlComp.scheme == 'https' or bSSL:
                        elem[ 'PortNumber' ] = '443'
                    elif urlComp.scheme == 'http' :
                        elem[ 'PortNumber' ] = '80'
                else :
                    elem[ 'PortNumber' ] = urlComp.port
                if urlComp.hostname is not None:
                    elem[ 'IpAddress' ] = urlComp.hostname
                else :
                    raise Exception( 'web socket URL is not valid' ) 
            else :
                elem.pop( 'DestURL', None )

    except Exception as err:
        print( "Error UpdateTestCfg", err, file=sys.stderr )

    return

def tempname()->str:
    f, strName = mkstemp( prefix='rpcfgtmp', dir='/tmp')
    os.close(f)
    return strName

def OverwriteJsonFile( strPath : str, jsonVal )->int:
    ret = 0
    tempfile = ""
    bRemove = False
    try:
        global g_passDlg
        if g_passDlg is not None:
            bCmdLine = False
        else:
            bCmdLine = True

        stat_info = os.stat( strPath )
        uid = stat_info.st_uid

        if uid == os.geteuid() :
            fp = open(strPath, "w")
            json.dump( jsonVal, fp, indent=4)
            fp.close()
            ret = 0
            return ret

        if uid != 0:
            ret = -errno.EACCES
            return ret

        tempfile = tempname()
        if len(tempfile) == 0:
            ret = -errno.EEXIST
            return ret

        bRemove = True
        fp = open( tempfile, "w" )
        json.dump( jsonVal, fp, indent=4)
        fp.close()
        bSudo = IsSudoAvailable()
        if bCmdLine :
            if bSudo:
                strCmd = "sudo cp " + tempfile + " " + strPath
                ret = rpcf_system( strCmd )
            else:
                strCmd = "su -c 'cp " + tempfile + " " + strPath + "'"
                ret = rpcf_system( strCmd )

            return ret

        if bSudo:
            strCmd = "sudo -n cp " + tempfile + " " + strPath
            ret = rpcf_system( strCmd )
        else:
            strCmd = "su -c 'cp " + tempfile + " " + strPath + "'"
            ret = rpcf_system( strCmd )

        if ret == 0 :
            return ret

        if bSudo:
            strCmd = "sudo cp " + tempfile + \
                " " + strPath 
            ret = rpcf_system( strCmd )
        else:
            ret = errno.ENOTSUP

        if ret == 0 :
            return ret

    except Exception as err:
        if ret == 0:
            ret = -errno.EFAULT
    finally:
        if bRemove:
            os.unlink( tempfile )

    return ret

def WriteTestCfg( strPath, jsonVal ) :
    return OverwriteJsonFile( strPath, jsonVal )

def ExtraUpdateBtinrt(
    drvVal : object, destVal : object ):
    try:
        oFactories = None
        if 'Modules' in drvVal :
            oModules = drvVal[ 'Modules' ]
            for oModule in oModules :
                if oModule[ 'ModName' ] != 'rpcrouter':
                    continue
                oFactories = oModule[ "ClassFactories" ]
                break
        if oFactories is None:
            return

        destList = [ "./libbtinrt.so" ]
        destList.extend( oFactories )
        destList.remove( "./libfuseif.so" )
        destVal[ "ClassFactories" ] = destList
    except Exception as err:
        pass

def ExtraUpdateAppmon( destVal : object ):
    try:
        objs = destVal[ 'Objects' ]
        for elem in objs :
            objName = elem[ 'ObjectName' ]
            if 'AppManager' in objName or 'SimpleAuth' in objName:
                if not '_SvrSkel' in objName:
                    elem[ 'ProxyPortClass' ] = 'DBusLocalPdo'
    except Exception as err:
        print( err )

def ExportTestCfgsTo( cfgList:list, destPath:str ):
    testDescs = [ 'echodesc.json', 'hwdesc.json', 'btinrt.json', 'appmondesc.json' ]
    if IsFeatureEnabled( 'testcases' ):
        testDescs.extend(  [ "actcdesc.json",
            "asyndesc.json",
            "evtdesc.json",
            "kadesc.json",
            "prdesc.json",
            "sfdesc.json",
            "stmdesc.json" ] )

    paths = GetTestPaths( destPath )
    pathVal = ReadTestCfg( paths, testDescs[ 0 ] )
    if pathVal is None :
        paths = GetTestPaths()

    ret = 0
    for testDesc in testDescs :
        pathVal = ReadTestCfg( paths, testDesc )
        if pathVal is None :
            continue
        UpdateTestCfg( pathVal, cfgList )

        if testDesc == "btinrt.json" :
            ExtraUpdateBtinrt( cfgList[ 2 ], pathVal[ 1 ] )

        elif testDesc == 'appmondesc.json':
            ExtraUpdateAppmon( pathVal[ 1 ] )

        ret = WriteTestCfg(
            destPath + "/" + testDesc,
            pathVal[ 1 ] )
        if ret < 0 :
            break

    if ret < 0 :
        return ret
    paths = GetPyTestPaths()
    pathVal = ReadTestCfg( paths, 'sfdesc.json' )
    if pathVal is not None :
        UpdateTestCfg( pathVal, cfgList )
        ret = WriteTestCfg(
            destPath + "/sfdesc-py.json",
            pathVal[ 1 ] )
    return ret

def ExportTestCfgs( cfgList:list ):
    testDescs = [ 'echodesc.json', 'hwdesc.json', 'btinrt.json', 'appmondesc.json' ]
    if IsFeatureEnabled( 'testcases' ):
        testDescs.extend(  [ "actcdesc.json",
            "asyndesc.json",
            "evtdesc.json",
            "kadesc.json",
            "prdesc.json",
            "sfdesc.json",
            "stmdesc.json" ] )

    ret = 0
    paths = GetTestPaths()
    for testDesc in testDescs :
        pathVal = ReadTestCfg( paths, testDesc )
        if pathVal is None :
            continue
        UpdateTestCfg( pathVal, cfgList )

        if testDesc == "btinrt.json" :
            ExtraUpdateBtinrt( cfgList[ 2 ], pathVal[ 1 ] )

        elif testDesc == 'appmondesc.json':
            ExtraUpdateAppmon( pathVal[ 1 ] )

        ret = WriteTestCfg( pathVal[ 0 ], pathVal[ 1 ] )
        if ret < 0 :
            break

        # update the copy of appmondesc.json in appmonui.tar.gz
        if testDesc == 'appmondesc.json':
            cmdLine = f"path=$(dirname {pathVal[0]});"
            cmdLine += "cd $path; if [ ! -f appmonui.tar.gz ]; then exit 1; fi;"
            cmdLine += "tempdir=`mktemp -d`;curdir=$(pwd);cd $tempdir;tar -zxf $curdir/appmonui.tar.gz;"
            if IsSudoAvailable():
                cmdLine += "cp $curdir/appmondesc.json ./;sudo tar -zcf $curdir/appmonui.tar.gz *; cd $curdir; rm -rf $tempdir;"
            else:
                cmdLine += "cp $curdir/appmondesc.json ./;su -c \"tar -zcf $curdir/appmonui.tar.gz *\"; cd $curdir; rm -rf $tempdir;"
            rpcf_system( cmdLine )


    if ret < 0 :
        return ret

    paths = GetPyTestPaths()
    pathVal = ReadTestCfg( paths, 'sfdesc.json' )
    if pathVal is not None :
        UpdateTestCfg( pathVal, cfgList )
        ret = WriteTestCfg( pathVal[ 0 ], pathVal[ 1 ] )
    return ret

def IsSSLEnabled( drvCfg : dict, portClass='TcpStreamPdo2' ) -> Tuple[ int, bool ] :
    try:
        if drvCfg is None :
            return ( -errno.EINVAL, None )
        if 'Match' not in drvCfg :
            return ( -errno.ENOENT, None )
        oMatches = drvCfg[ 'Match']
        for oMatch in oMatches:
            if not 'PortClass' in oMatch:
                continue
            if oMatch[ 'PortClass' ] != portClass:
                continue
            if not 'ProbeSequence' in oMatch:
                return ( -errno.ENOENT, None )
            oDrvArray = oMatch[ 'ProbeSequence' ]
            if len( oDrvArray ) == 0:
                return ( -errno.ENOENT, None )
            if oDrvArray[ 0 ] == 'RpcOpenSSLFido' :
                return ( 0, True )
            elif oDrvArray[ 0 ] == 'RpcGmSSLFido' :
                return ( 0, False )
            break
        return ( -errno.ENOENT, None )
    except Exception as err:
        return ( -errno.EFAULT, None )

def IsUsingGmSSL( drvCfg : dict, portClass='TcpStreamPdo2' ) -> Tuple[ int, bool ]:
    try:
        if drvCfg is None :
            return ( -errno.EINVAL, None )
        for port in drvCfg[ 'Match' ] :
            if port[ 'PortClass'] == portClass :
                if 'UsingGmSSL' in port:
                    if port[ 'UsingGmSSL' ] == 'true':
                        return ( 0, True )
                return ( 0, False )
        return ( -errno.ENOENT, None )
    except Exception as err:
        return ( -errno.EFAULT, None )

def SetUsingGmSSL( drvCfg : dict, bEnable : bool, portClass='TcpStreamPdo2' ) -> int:
    try:
        if drvCfg is None :
            return -errno.EINVAL
        for port in drvCfg[ 'Match' ] :
            if port[ 'PortClass'] == portClass :
                if bEnable :
                    port[ 'UsingGmSSL' ] = 'true'
                else:
                    port[ 'UsingGmSSL' ] = 'false'
                return 0
        return -errno.ENOENT
    except Exception as err:
        return -errno.EFAULT

def IsVerifyPeer( drvCfg : dict, portClass : str ) -> Tuple[ int, bool ]:
    try:
        if drvCfg is None :
            return ( -errno.EINVAL, None )
        for port in drvCfg[ 'Ports' ] :
            if port[ 'PortClass'] != portClass :
                continue
            if not 'Parameters' in port : 
                break
            oParams = port[ 'Parameters' ]
            if 'VerifyPeer' in oParams:
                if oParams[ 'VerifyPeer' ] == 'true':
                    return ( 0, True )
                elif oParams[ 'VerifyPeer' ] == 'false':
                    return ( 0, False )
            return -errno.EINVAL, None
        return ( -errno.ENOENT, None )
    except Exception as err:
        return ( -errno.EFAULT, None )

def SetVerifyPeer( drvCfg : dict, bEnable : bool, portClass : str ) -> int:
    try:
        if drvCfg is None :
            return -errno.EINVAL
        for port in drvCfg[ 'Ports' ] :
            if port[ 'PortClass'] != portClass :
                continue
            if not 'Parameters' in port : 
                port[ 'Parameters' ] = dict()
            oParams = port[ 'Parameters' ]
            if bEnable :
                oParams[ 'VerifyPeer' ] = 'true'
            else:
                oParams[ 'VerifyPeer' ] = 'false'
            return 0
        return -errno.ENOENT
    except Exception as err:
        return -errno.EFAULT

def LoadConfigFiles( path : str) :
    dir_path = os.path.dirname(os.path.realpath(__file__))
    parent_dir = os.path.basename( dir_path )
    paths = []
    curDir = dir_path
    if path is None:
        if parent_dir == "rpcf" :
            #paths.append( "." )
            paths.append( curDir + "/../../etc/rpcf" )
            paths.append( "/etc/rpcf")
        else:
            paths.append( curDir + "/../ipc" )
            paths.append( curDir + "/../rpc/router" )
            paths.append( curDir + "/../rpc/security" )
            paths.append( curDir + "/../rpc/security/oa2check" )
            paths.append( curDir + "/../test/iftest" )
            paths.append( curDir + "/../test/btinrt" )
            paths.append( curDir + "/../test/helloworld" )
    else:
        paths.append( path )
    
    count = 8
    jsonvals = [ None ] * 8
    for strPath in paths :
        try:
            if jsonvals[ 0 ] is None :
                drvfile = strPath + "/driver.json"
                fp = open( drvfile, "r" )
                jsonvals[ 0 ] = [drvfile, json.load(fp) ]
                fp.close()
                count-=1
        except Exception as err :
            pass
        try:
            if jsonvals[ 1 ] is None :
                rtfile = strPath + "/router.json"
                fp = open( rtfile, "r" )
                jsonvals[ 1 ] = [rtfile, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass

        try:
            if jsonvals[ 2 ] is None :
                rtaufile = strPath + "/rtauth.json"
                fp = open( rtaufile, "r" )
                jsonvals[ 2 ] = [rtaufile, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass
        
        try:
            if jsonvals[ 3 ] is None :
                auprxyfile = strPath + "/authprxy.json"
                fp = open( auprxyfile, "r" )
                jsonvals[ 3 ] = [auprxyfile, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass            

        try:
            if jsonvals[ 4 ] is None and IsFeatureEnabled( 'js' ) :
                oa2desc = strPath + "/oa2checkdesc.json"
                fp = open( oa2desc, "r" )
                jsonvals[ 4 ] = [oa2desc, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass            

        try:
            if jsonvals[ 5 ] is None :
                echodesc = strPath + "/echodesc.json"
                fp = open( echodesc, "r" )
                jsonvals[ 5 ] = [echodesc, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass            

        try:
            if jsonvals[ 6 ] is None :
                hwdesc = strPath + "/hwdesc.json"
                fp = open( hwdesc, "r" )
                jsonvals[ 6 ] = [hwdesc, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass            

        try:
            if jsonvals[ 7 ] is None :
                btinrtdesc = strPath + "/btinrt.json"
                fp = open( btinrtdesc, "r" )
                jsonvals[ 7 ] = [btinrtdesc, json.load(fp)]
                fp.close()
                count-=1
        except Exception as err :
            pass            

        if count == 0:
            break

    if count == 0:
        return jsonvals

    idx = 0
    fn = None
    for i in jsonvals: 
        if i is not None:
            idx+=1
            continue
        if idx == 0:
            fn = "driver.json"
        elif idx == 1:
            fn = "router.json"
        elif idx == 2:
            fn = "rtauth.json"
        elif idx == 3:
            fn = "authprxy.json"
        elif idx == 4 and IsFeatureEnabled( 'js' ):
            fn = "oa2checkdesc.json"
        elif idx == 5 :
            fn = "echodesc.json"
        elif idx == 6:
            fn = "hwdesc.json"
        elif idx == 7:
            fn = "btinrt.json"
    if fn is not None:
        raise Exception( "Error open " + fn )
            
    return jsonvals

def Update_AuthPrxy( initCfg: dict, drvFile : list,
    bServer: bool, destDir : str, drvVal : object ) -> int :

    ret = 0
    apVal = drvFile[ 1 ]
    proxies = apVal['Objects']
    if proxies is None or len( proxies ) == 0:
        raise Exception("Error bad content in authprxy.json") 

    oConns = None
    oConn0 = None
    if 'Connections' in initCfg :
        oConns = initCfg[ 'Connections' ]
        if len( oConns ) > 0 :
            oConn0 = oConns[ 0 ]

    authInfo = None
    kdcIp = None
    userName = None
    if ( 'Security' in initCfg and
        'AuthInfo' in initCfg[ 'Security' ] ):
        authInfo = deepcopy(
            initCfg[ 'Security' ][ 'AuthInfo' ] )

        if 'AuthMech' not in authInfo :
            raise Exception( "Error missing 'AuthMech' in initcfg.json" )
        if authInfo[ 'AuthMech' ] != "krb5" :
            #update the testcfgs
            oConn0[ 'BindAddr' ] = oConn0[ 'IpAddress' ]
            cfgList = [ oConn0, authInfo, drvVal, oConns ]
            if destDir is None :
                ret = ExportTestCfgs( cfgList )
            else:
                ret = ExportTestCfgsTo( cfgList, destDir )
            oConn0.pop( 'BindAddr', None )
            return ret

        if bServer :
            kdcIp = authInfo[ 'KdcIp' ]
        authInfo.pop( 'KdcIp', None )
        if 'UserName' in authInfo :
            userName = authInfo[ 'UserName' ]

    for proxy in proxies :
        objName = proxy[ 'ObjectName' ]
        if objName == 'K5AuthServer' or objName == 'KdcChannel':
            if oConn0 is None:
                continue
            elem = proxy
            elem[ 'IpAddress' ] = oConn0[ 'IpAddress' ]
            elem[ 'PortNumber' ] = oConn0[ 'PortNumber' ]
            elem[ 'Compression' ] = oConn0[ 'Compression' ]
            elem[ 'EnableSSL' ] = oConn0[ 'EnableSSL' ]

            if objName == 'K5AuthServer' :
                elem.pop( 'HasAuth', None )
            else :
                if authInfo is not None:
                    authInfo[ 'UserName' ] = 'kdcclient'
                    elem[ 'AuthInfo' ] = authInfo

            bSSL = False
            if elem[ 'EnableSSL' ] == 'true' :
                bSSL = True
            elem[ 'EnableWS' ] = oConn0[ 'EnableWS' ]
            if elem[ 'EnableWS' ] == 'true' :
                elem[ 'DestURL'] = oConn0[ 'DestURL' ]
                #urlComp = urlparse( elem[ 'DestURL' ], scheme='https' )
                #if urlComp.port is None :
                #    if urlComp.scheme == 'https' or bSSL:
                #        elem[ 'PortNumber' ] = '443'
                #    elif urlComp.scheme == 'http' :
                #        elem[ 'PortNumber' ] = '80'
                #else :
                #    elem[ 'PortNumber' ] = urlComp.port
                #if urlComp.hostname is not None:
                #    elem[ 'IpAddress' ] = urlComp.hostname
                #else :
                #    raise Exception( 'web socket URL is not valid' ) 

        elif objName == 'KdcRelayServer' :
            if kdcIp is not None and bServer :
                proxy[ 'IpAddress' ] = kdcIp
            break

    if destDir is None :
        apPath = drvFile[ 0 ]
    else :
        apPath = destDir + "/authprxy.json"

    ret = OverwriteJsonFile( apPath, apVal )
    if ret < 0:
        return ret

    # update test configs
    if oConn0 is None :
        return ret

    if userName is not None :
        authInfo[ 'UserName' ] = userName

    oConn0[ 'BindAddr' ] = oConn0[ 'IpAddress' ]
    cfgList = [ oConn0, authInfo, drvVal, oConns ]
    if destDir is None :
        ret = ExportTestCfgs( cfgList )
    else:
        ret = ExportTestCfgsTo( cfgList, destDir )

    oConn0.pop( 'BindAddr', None )

    return ret

def Update_OA2Check( initCfg: dict, drvFile : list,
    bServer: bool, destDir : str, drvVal : object ) -> int :

    ret = 0
    if not IsFeatureEnabled( 'js' ):
        return 0
    apVal = drvFile[ 1 ]
    proxies = apVal['Objects']
    if proxies is None or len( proxies ) == 0:
        raise Exception("Error bad content in authprxy.json") 

    authInfo = None
    kdcIp = None
    userName = None
    if ( 'Security' in initCfg and
        'AuthInfo' in initCfg[ 'Security' ] ):
        authInfo = deepcopy(
            initCfg[ 'Security' ][ 'AuthInfo' ] )

        if 'AuthMech' not in authInfo :
            raise Exception( "Error missing 'AuthMech' in initcfg.json" )

        if authInfo[ 'AuthMech' ] != "OAuth2" :
            return 0

    if authInfo is None:
        return 0

    for proxy in proxies :
        objName = proxy[ 'ObjectName' ]
        if objName != 'OA2proxy':
            continue
        elem = proxy
        if 'OA2ChkIp' in authInfo:
            elem[ 'IpAddress'] = authInfo['OA2ChkIp']
            if 'OA2ChkPort' in authInfo:
                elem[ 'PortNumber' ] = authInfo['OA2ChkPort']
            else:
                elem[ 'PortNumber' ] = '4132'
            elem[ 'ProxyPortClass' ] = 'DBusProxyPdo'
            if 'OA2SSL' in authInfo:
                elem[ 'EnableSSL' ] = authInfo[ 'OA2SSL' ]
            else:
                elem[ 'EnableSSL' ] = 'false'
        else:
            elem[ 'ProxyPortClass' ] = 'DBusLocalPdo'
            elem.pop( 'IpAddress', None )
            elem.pop( 'PortNumber', None )
        break

    if destDir is None :
        apPath = drvFile[ 0 ]
    else :
        apPath = destDir + "/oa2checkdesc.json"

    ret = OverwriteJsonFile( apPath, apVal )
    if ret < 0:
        return ret

    return ret

def Update_Rtauth( initCfg: dict, drvFile: list,
    bServer: bool, destDir : str ) -> int :

    ret = 0
    if not bServer :
        return 0

    lbCfgs = []
    if 'LBGroup' in initCfg :
        lbCfgs = initCfg[ 'LBGroup' ]

    authInfo = None
    taskSched = 'RR'
    maxConn = 512
    if 'Security' in initCfg :
        security = initCfg[ 'Security' ]
        if 'AuthInfo' in security :
            authInfo = deepcopy( security[ 'AuthInfo' ] )
            authInfo.pop( 'UserName', None ) 
            authInfo.pop( 'KdcIp', None )

        if 'misc' in security :
            misc = security[ 'misc' ]
            if 'MaxConnections' in misc :
                maxConns = int( misc[ 'MaxConnections' ] )
            if 'TaskScheduler' in misc :
                taskSched = misc[ 'TaskScheduler' ]

    rtDesc = drvFile[ 1 ]
    svrObjs = rtDesc[ 'Objects' ]
    mhNodes = None

    if 'Multihop' in initCfg :
        mhNodes = initCfg[ 'Multihop' ]

    if svrObjs is not None and len( svrObjs ) > 0 :
        for svrObj in svrObjs :
            objName = svrObj[ 'ObjectName']
            if objName == 'RpcRouterBridgeAuthImpl' :
                if authInfo is not None :
                    ai2 = deepcopy( authInfo )
                    if ai2[ 'AuthMech'] == 'OAuth2':
                        if 'OA2ChkIp' in ai2:
                            ai2.pop( "OA2ChkIp")
                        if 'OA2ChkPort' in ai2:
                            ai2.pop( "OA2ChkPort")
                        if 'OA2SSL' in ai2:
                            ai2.pop( "OA2SSL")
                    svrObj[ 'AuthInfo'] = ai2
                #else :
                #    svrObj.pop( 'AuthInfo', None )

            if ( objName == 'RpcRouterBridgeAuthImpl' or
                 objName == 'RpcRouterBridgeImpl' ) :

                if lbCfgs is None or len( lbCfgs ) == 0:
                    svrObj.pop( 'LBGroup', None )
                else:
                    svrObj[ 'LBGroup' ] = lbCfgs

                if mhNodes is None or len( mhNodes ) == 0:
                    svrObj.pop( 'Nodes', None )
                elif 'Nodes' in svrObj :
                    nodes = svrObj[ 'Nodes' ]
                    if len( mhNodes ) < len( nodes ) :
                        nodes = nodes[ :len( mhNodes ) ]
                        svrObj[ 'Nodes' ] = nodes
                    elif len( mhNodes ) > len( nodes ) :
                        nodes += ( [ nodes[ 0 ] ] *
                            ( len( mhNodes ) - len( nodes ) ) )
                    for i in range( len( nodes ) ):
                        mhNode = mhNodes[ i ]
                        node = nodes[ i ]
                        for key, val in mhNode.items():
                            node[ key ] = val
                        if mhNode[ 'EnableWS' ] == "false" :
                            node.pop( 'DestURL', None )
                else :
                    svrObj[ 'Nodes'] = mhNodes

            elif objName == 'RpcRouterManagerImpl' :
                svrObj[ 'MaxRequests' ] = str( maxConns * 8  )
                svrObj[ 'MaxPendingRequests' ] = str( maxConns * 16  )
            elif ( objName == 'RpcReqForwarderAuthImpl' or
                objName == 'RpcReqForwarderImpl' ):
                svrObj[ 'TaskScheduler' ] = taskSched

    if destDir is None :
        rtauPath = drvFile[ 0 ]
    else :
        rtauPath = destDir + "/"
        rtauPath += os.path.basename( drvFile[ 0 ] )

    return OverwriteJsonFile( rtauPath, rtDesc )

def DefaultIfCfg() -> dict :
    defCfg = dict()
    defCfg[ "AddrFormat" ]= "ipv4"
    defCfg[ "Protocol" ]= "native"
    defCfg[ "PortNumber" ]= "4132"
    defCfg[ "BindAddr"] = "127.0.0.1"
    defCfg[ "PdoClass"] = "TcpStreamPdo2"
    defCfg[ "Compression" ]= "true"
    defCfg[ "EnableWS" ]= "false"
    defCfg[ "EnableSSL" ]= "false"
    defCfg[ "ConnRecover" ]= "false"
    defCfg[ "HasAuth" ]= "false"
    defCfg[ "DestURL" ]= "https://www.example.com"
    defCfg[ "EnableBPS" ]= "false"
    return defCfg

def CheckIpAddr( addr ) :
    try:
        socket.inet_aton(addr)
        return 'ipv4'
    except socket.error:
        pass

    try:
        socket.inet_pton(socket.AF_INET6, addr)
        return 'ipv6'
    except socket.error:
        pass
    return None

def Update_Drv( initCfg: dict, drvFile : list,
    bServer : bool, destDir : str ) -> int :

    drvVal = drvFile[ 1 ]

    if 'Ports' in drvVal :
        ports = drvVal['Ports']
    else :
        return -errno.ENOENT

    strMech = ""
    bGmSSL = False
    while 'Security' in initCfg :
        security = initCfg[ 'Security' ]
        if 'SSLCred' in security :
            sslCred = security[ 'SSLCred' ]
            if 'KeyFile' in sslCred :
                keyPath = sslCred[ 'KeyFile' ]
            else:
                keyPath = ''

            if 'CertFile' in sslCred :
                certPath = sslCred[ 'CertFile' ]
            else:
                certPath = ''

            if 'CACertFile' in sslCred :
                cacertPath = sslCred[ 'CACertFile' ]
            else:
                cacertPath = ''

            if 'SecretFile' in sslCred :
                secretPath = sslCred[ 'SecretFile' ]
            else:
                secretPath = ''

            bVerifyPeer = False
            strVerifyPeer = sslCred.get( 'VerifyPeer' )
            if strVerifyPeer == 'true' :
                bVerifyPeer = True
            elif strVerifyPeer == 'false' or strVerifyPeer is None :
                bVerifyPeer = False
            else :
                raise Exception( "invalid value" )

            strPort = 'RpcOpenSSLFido'
            UsingGmSSL = sslCred.get( 'UsingGmSSL' )
            if UsingGmSSL == 'true' :
                strPort = 'RpcGmSSLFido'
                bGmSSL = True
            elif UsingGmSSL == 'false' or UsingGmSSL is None :
                bGmSSL = False
            else :
                raise Exception( "invalid value" )

            for port in ports :
                if port[ 'PortClass'] != strPort :
                    continue
                sslFiles = port[ 'Parameters']
                if sslFiles is None :
                    continue
                sslFiles[ "KeyFile"] = keyPath
                sslFiles[ "CertFile"] = certPath
                sslFiles[ 'CACertFile' ] = cacertPath
                sslFiles[ 'SecretFile' ] = secretPath
                break
            SetUsingGmSSL( drvVal, bGmSSL )
            SetVerifyPeer( drvVal, bVerifyPeer, strPort )
        if 'AuthInfo' in security:
            authInfo = security[ 'AuthInfo' ]
            if 'AuthMech' in authInfo :
                strMech = authInfo[ 'AuthMech' ]

        if 'misc' in security and bServer :
            misc = security[ 'misc' ]
            for port in ports :
                if port[ 'PortClass'] != 'RpcTcpBusPort' :
                    continue
                if 'MaxConnections' in misc :
                    port[ 'MaxConnections' ] = misc[ 'MaxConnections' ]
                else :
                    port[ 'MaxConnections' ] = '512'
                break
        break


    defConn = dict()
    defConn[ "AddrFormat" ]= "ipv4"
    defConn[ "Protocol" ]= "native"
    defConn[ "PortNumber" ]= "4132"
    defConn[ "IpAddress"] = "127.0.0.1"
    defConn[ "PdoClass"] = "TcpStreamPdo2"
    defConn[ "Compression" ]= "true"
    defConn[ "EnableWS" ]= "false"
    defConn[ "EnableSSL" ]= "false"
    defConn[ "ConnRecover" ]= "false"
    defConn[ "HasAuth" ]= "false"
    defConn[ "DestURL" ]= "https://www.example.com"
    defConn[ "EnableBPS" ]= "false"

    oConns = None
    if bServer and 'Connections' not in initCfg:
        oConns = [ defConn, ]

    while bServer and 'Connections' in initCfg:
        oConns = initCfg[ 'Connections' ]
        if len( oConns ) == 0 :
            oConns.append( defConn )

        for port in ports :
            if port[ 'PortClass'] != 'RpcTcpBusPort' :
                continue
            ifList = []
            for i in range( len( oConns ) ) :
                ifCfg = dict()
                oConn = oConns[ i ]
                bBindAddr = True
                for key, val in oConn.items() :
                    if key == 'IpAddress' :
                        ifCfg[ 'BindAddr' ] = val
                        strFormat = CheckIpAddr( val )
                    elif key == 'HasAuth' and val == 'true' :
                        ifCfg[ key ] = val
                        ifCfg[ 'AuthMech' ] = strMech
                    elif key == 'AuthMech' :
                        pass
                    elif key == 'BindTo' and val == 'false':
                        bBindAddr = False
                    else :
                        ifCfg[ key ] = val
                if oConn[ 'EnableWS' ] == "false" :
                    ifCfg.pop( "DestURL", None )

                if strFormat is None :
                    strFormat = 'invalid'
                if not bBindAddr :
                    if strFormat != 'ipv6':
                        ifCfg[ 'BindAddr' ] = '0.0.0.0'
                    else:
                        ifCfg[ 'BindAddr' ] = '::/0'
                if 'PdoClass' not in ifCfg :
                    ifCfg[ 'PdoClass' ] = "TcpStreamPdo2"
                if 'ConnRecover' not in ifCfg :
                    ifCfg[ 'ConnRecover' ] = "false"
                if 'EnableBPS' not in ifCfg :
                    ifCfg[ 'EnableBPS' ] = "false"
                if 'Protocol' not in ifCfg :
                    ifCfg[ "Protocol" ] = "native"
                if 'AddrFormat' not in ifCfg:
                    ifCfg[ 'AddrFormat' ] = strFormat

                ifList.append( ifCfg )

            port[ 'Parameters'] = ifList
            break
        break

    if not bServer and 'Connections' in initCfg:
        oConns = initCfg[ 'Connections' ]

    bAuth = False
    bSSL = False
    if oConns is not None:
        for oConn in oConns:
            if 'HasAuth' in oConn :
                if oConn[ 'HasAuth' ] == 'true' :
                    bAuth = True
            if 'EnableSSL' in oConn:
                if oConn[ 'EnableSSL' ] == 'true' :
                    bSSL = True

    try:
        if 'Match' in drvVal :
            oMatches = drvVal[ 'Match' ]
            for oMatch in oMatches:
                if oMatch[ 'PortClass' ] != "TcpStreamPdo2":
                    continue
                oSeq = [ "RpcNatProtoFdoDrv", "RpcTcpFidoDrv" ]
                if bAuth and strMech == 'krb5' :
                    oSeq.insert( 0, "RpcSecFidoDrv" )
                if bSSL :
                    oSeq.insert( 0, "RpcWebSockFidoDrv" )
                    if bGmSSL:
                        oSeq.insert( 0, "RpcGmSSLFidoDrv" )
                    else:
                        oSeq.insert( 0, "RpcOpenSSLFidoDrv" )
                oMatch[ 'ProbeSequence' ] = oSeq
                break

        if 'Modules' in drvVal :
            oModules = drvVal[ 'Modules' ]
            for oModule in oModules :
                if oModule[ 'ModName' ] != 'rpcrouter':
                    continue
                oFactories=[]
                if IsFeatureEnabled( "fuse3" ):
                    oFactories.append( './libfuseif.so' )
                if bAuth :
                    oFactories.append ( './libauth.so' )
                    if strMech == 'OAuth2' or strMech == 'SimpAuth':
                        oFactories.append ( './libregfs.so' )
                if bSSL:
                    if bGmSSL:
                        oFactories.append( './libgmsslpt.so' )
                    else:
                        oFactories.append( './libsslpt.so' )
                    oFactories.append( './libwspt.so' )
                oModule[ "ClassFactories" ] = oFactories
                break

    except Exception as err:
        pass

    if destDir is None:
        drvPath = drvFile[ 0 ]
    else:
        drvPath = destDir + "/driver.json"

    return OverwriteJsonFile( drvPath, drvVal )

def Update_InitCfg( cfgPath : str, destDir : str,
    passDlg:object = None ) -> int :
    ret = 0
    try:
        global g_passDlg
        g_passDlg = passDlg
        fp = open( cfgPath, "r" )
        initCfg = json.load( fp )
        fp.close()

        if 'InstToSvr' in initCfg:
            strVal = initCfg[ 'InstToSvr' ]
        else:
            strVal = initCfg[ 'IsServer' ]

        if strVal == 'true' :
            bServer = True
        elif strVal == 'false' :
            bServer = False
        else:
            return -errno.EINVAL

        jsonFiles = LoadConfigFiles( None )
        if jsonFiles is None :
            return -errno.EFAULT

        ret = Update_Drv(
            initCfg, jsonFiles[ 0 ], bServer, destDir )
        if ret < 0 :
            return ret

        ret = Update_Rtauth(
            initCfg, jsonFiles[ 1 ], bServer, destDir )
        if ret < 0 :
            return ret

        ret = Update_Rtauth(
            initCfg, jsonFiles[ 2 ], bServer, destDir )
        if ret < 0 :
            return ret

        drvVal = jsonFiles[ 0 ][ 1 ]
        ret = Update_AuthPrxy( initCfg,
            jsonFiles[ 3 ], bServer, destDir, drvVal )
        if ret < 0 :
            return ret

        drvVal = jsonFiles[ 0 ][ 1 ]
        ret = Update_OA2Check( initCfg,
            jsonFiles[ 4 ], bServer, destDir, drvVal )
        if ret < 0 :
            return ret

    except Exception as err:
        text = "Update_InitCfg failed:" + str( err )
        exc_type, exc_obj, exc_tb = sys.exc_info()
        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
        second_text = "@" + fname + ":" + str(exc_tb.tb_lineno)
        print( text, second_text )
        ret = -errno.EFAULT

    return ret


if __name__ == "__main__" :
    parser = argparse.ArgumentParser(description="Update rpc-frmwrk configuration files based on initcfg.json")
    parser.add_argument("initcfg", help="Path to initcfg.json")
    args = parser.parse_args()

    # Call the update function with the parsed arguments
    ret = Update_InitCfg(args.initcfg, None)
    quit( -ret )
